package com.javen.demo;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

/**
 * @author javen
 * 
 * 死锁是指两个或者两个以上进程执行中，因抢夺资源而造成的一种相互等待的现象，若无外力的干涉那他们都无法进行下去
 * 死锁原因：
 * 1、系统资源不足
 * 2、进程运行推进的顺序不合适
 * 3、资源分配不当
 * 造成死锁的四个条件：
 * 1、互斥条件
 * 2、占有且申请
 * 3、不可强占
 * 4、循环等待条件
 *
 * 解决办法：
 * 1、死锁预防：通过设置某些限制条件，去破坏死锁的四个条件中的一个或几个条件，来预防发生死锁。
 * 但由于所施加的限制条件往往太严格，因而导致系统资源利用率和系统吞吐量降低。
 * 2、死锁避免：在资源分配过程中若预测有发生死锁的可能性，则加以避免。这种方法的关键是确定资源分配的安全性。
 * 3、死锁检测与恢复：不须实现采取任何限制性措施，而是允许系统在运行过程发生死锁，
 * 但可通过系统设置的检测机构及时检测出死锁的发生，并精确地确定于死锁相关的进程和资源，
 * 然后采取适当的措施，从系统中将已发生的死锁清除掉。
 *
 * 解决方案：
 * jps -l          查看进程号
 * jstack 进程号    找到死锁
 */
@Slf4j
public class ThreadDemo {

    public static void main(String[] args) {

        new ThreadExtends().start();

        new Thread(() -> log.info("{} thread Runnable run ...", Thread.currentThread().getName()), "T1").start();

        new Thread(new TreadImpl(), "T2").start();

        FutureTask<String> futureTask = new FutureTask<>(new TreadCallable());

        new Thread(futureTask, "T3").start();
        try {
            // futureTask.get() 会导致堵塞，直到线程计算完成
            log.info(" futureTask result {}", futureTask.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }

        log.info("系统核数 {}", Runtime.getRuntime().availableProcessors());

        // 死锁
        String lockOne = "one";
        String lockTwo = "two";

        new Thread(new HoldLock(lockOne,lockTwo),"one").start();
        new Thread(new HoldLock(lockTwo,lockOne),"two").start();
    }
}

@Slf4j
class ThreadExtends extends Thread{
    @Override
    public void run() {
        super.run();
        log.info("{} ThreadExtends run ...", this.getName());
    }
}

@Slf4j
class TreadImpl implements Runnable {

    @Override
    public void run() {
        log.info("{} implements Runnable run ...", Thread.currentThread().getName());
    }
}


@Slf4j
class TreadCallable implements Callable<String> {

    @Override
    public String call() {
        try {
            TimeUnit.SECONDS.sleep(5);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Callable call.." + Thread.currentThread().getName();
    }
}

/**
 * 死锁
 */
@Slf4j
class HoldLock implements Runnable {
    private final String lockOne;
    private final String lockTwo;

    public HoldLock(String lockOne, String lockTwo) {
        this.lockOne = lockOne;
        this.lockTwo = lockTwo;
    }

    @Override
    public void run() {
        synchronized (lockOne) {
            log.info("{} 自己持有：{},尝试获得：{}", Thread.currentThread().getName(), lockOne, lockTwo);

            synchronized (lockTwo) {
                log.info("{} 自己持有：{},尝试获得：{}", Thread.currentThread().getName(), lockTwo, lockOne);
            }
        }
    }
}


